package dfw

import (
	"bufio"
	"dfws/rsa"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"regexp"
	"strconv"
	"time"
)

func StartClient(workdir string, id string, host string, port int, timeout int, testUrl string, testRegex string) {
	if testUrl == "" {
		testUrl = "https://api.ipify.org"
	}
	ip, err := getMyNetIp(testUrl, testRegex)
	if err != nil {
		log.Println(`获取本地外网IP错误 :`, err)
		return
	}
	if ip == "" {
		log.Println(`获取本地外网IP为空。请检查正则表达式是否匹配`)
		return
	}
	if err := rsa.LoadPublicKey(workdir, id); err != nil {
		log.Println(`加载秘钥错误 error :`, err)
		return
	}
	if id == "" {
		host = "test"
	}
	if port > 65535 || port < 1 {
		port = 6760
	}
	if timeout == 0 {
		timeout = 5
	}
	if host == "" {
		host = "sction.org"
	}
	address := host + ":" + strconv.Itoa(port)
	/**
	  使用Dial函数链接服务端,其函数签名如下所示:
	      func Dial(network, address string) (Conn, error)
	  以下是对函数签名的各参数说明:
	      network:
	          指定客户端socket的协议,如tcp/udp,该协议应该和需要链接服务端的协议一致哟~
	      address:
	          指定客户端需要链接服务端的socket信息,即指定服务端的IP地址和端口
	*/
	conn, err := net.DialTimeout("tcp", address, time.Duration(timeout)*time.Second)
	if err != nil {
		log.Println(`connect error :`, err, address)
		return
	}
	defer conn.Close()
	log.Println("connected.", address)
	/**
	  定义需要发送的数据,第一次给服务端发送要发的长度
	*/
	data, err := rsa.RSA.PubKeyENCTYPT([]byte(ip))
	if err != nil {
		log.Println(`加密数据 error :`, err)
	}

	netDataRequest := NetData{
		Id:     id,
		Data:   data,
		Action: []byte("dfw"),
	}
	packetData, err := Packet(netDataRequest)
	if err != nil {
		log.Println(`封装请求数据 error :`, err)
		return
	}
	conn.Write(packetData)

	reader := bufio.NewReader(conn)
	//读取数据
	netDataResponse, err := UnPack(reader)
	if err != nil {
		log.Println(`解包数据 error :`, err)
		return
	}
	result, err := rsa.RSA.PubKeyDECRYPT(netDataResponse.Data)
	if err != nil {
		log.Println(`解密响应数据 error :`, err)
	}

	log.Println("result: ", string(result))
}

func getMyNetIp(testUrl string, testRegex string) (string, error) {
	log.Println("url: ", testUrl)
	client := http.Client{}
	request, err := http.NewRequest("GET", testUrl, nil)
	request.Header.Add("User-Agent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36 UOS")
	if err != nil {
		return "", err
	}
	//处理返回结果
	response, _ := client.Do(request)
	defer response.Body.Close()

	log.Println("code: ", response.StatusCode)
	body, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return "", err
	}
	var txt = string(body)
	ip := txt
	if testRegex != "" {
		regex := regexp.MustCompile(testRegex)
		results := regex.FindStringSubmatch(txt)
		log.Println("result length:", len(results))
		if len(results) > 1 {
			ip = results[1]
		} else {
			ip = ""
			log.Println("未匹配数据: ", txt)
			log.Println("testRegex: ", testRegex)
		}
	}
	log.Println("ip: ", ip)
	return ip, nil
}
